//////////////////////////////////////////////////////////////////////
////                                                              ////
////  VariableFrequencyDCM.v                                      ////
////                                                              ////
////                                                              ////
////  This file is part of the "Pico E12" project                 ////
////                                                              ////
////                                                              ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2005, Pico Computing, INC.                     ////
//// http://www.picocomputing.com                                 ////
////                                                              ////
//// This source file may be used and distributed without         ////
//// restriction provided that this copyright statement is not    ////
//// removed from the file and that any derivative work contains  ////
//// the original copyright notice and the associated disclaimer. ////
////                                                              ////
//// This source file is free software; you can redistribute it   ////
//// and/or modify it under the terms of the GNU Lesser General   ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any   ////
//// later version.                                               ////
////                                                              ////
//// This source is distributed in the hope that it will be       ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
//// PURPOSE.  See the GNU Lesser General Public License for more ////
//// details.                                                     ////
////                                                              ////
//// You should have received a copy of the GNU Lesser General    ////
//// Public License along with this source; if not, download it   ////
//// from http://www.opencores.org/lgpl.shtml                     ////
////                                                              ////
////////////////////////////////////////////////////////////////////JF

`include "PicoDefines.v"

module VariableFrequencyDCM(CLOCKIN, ClockOutPreBuf, ClockOut, MemRead, MemWrite, MemAddress, DataIn, DataOut);

input CLOCKIN;                                                 //50 MHz Free Running Clock Input
output ClockOutPreBuf;                                         //Variable Frequency Clock Output (No BUFG)
output ClockOut;                                               //Variable Frequency Clock Output (BUFG)
input MemRead;                                                 //Compact Flash Memory Read
input MemWrite;                                                //Compact Flash Memory Write
input [31:1]MemAddress;                                        //Compact Flash Memory Address
input [15:0]DataIn;                                            //Host -> Peripheral
output [15:0]DataOut;                                          //Host <- Peripheral

wire Feedback;                                                 //DCM Clock Feedback Out - It would be better to use no feedback, but the kills the timing score
wire FeedbackBuffered;                                         //DCM Clock Feedback In
wire ClockOutPreBuf;                                           //Variable Frequency Clock Output (Before Clock Distribution Logic)

wire [6:0]DCMAddress;                                          //Address
reg DCMEnable;                                                 //Read and General Enable
reg DCMWE;                                                     //Write Enable
reg DCMReset;                                                  //Reset
wire [15:0]DCMOut;                                             //DCM Reconfiguration Data Output
wire DCMReady;                                                 //Ready status line
wire DCMLocked;                                                //Locked status line (clock output is valid when high)
wire DCMPSDone; 																//Phase Shift Done

wire DCMStatusRead;                                            //Status Read 

reg ArmWrite;                                                  //This goes high after a Compact Flash write has occured

wire [15:0]DCMDataOut;                                         //Multiplexed DCM Data Output
wire [15:0]Status;                                             //Raw Status 
wire [15:0]StatusDataOut;                                      //Multiplexed Status Data Output

//synthesis attribute INIT of DCMEnable is 0;
//synthesis attribute INIT of DCMWE is 0;
//synthesis attribute INIT of DCMReset is 0;
//synthesis attribute INIT of ArmWrite is 0;

//Address and Function Decoding
assign DCMAddress[6:0] = MemAddress[7:1];                      //DCM must be located on a 256 byte boundary
assign DCMStatusRead	= (MemRead) && (MemAddress[31:1] == `VFDCM_STATUS_CONTROL_ADDRESS);
assign DCMRead = (MemRead) && (MemAddress[31:8] == `VFDCM_BASE_ADDRESS);
assign DCMWrite = (MemWrite) && (MemAddress[31:8] == `VFDCM_BASE_ADDRESS);

//Write Enable Control
always @(posedge CLOCKIN)
begin
   if (DCMWrite) begin 
	   ArmWrite <= 1;
   end
else
   if (ArmWrite) begin
	   DCMWE <= 1;
		ArmWrite <= 0;
   end
else
	DCMWE <= 0;
	ArmWrite <= 0;
end

//DCM Control Register
always @(posedge MemWrite) begin
   if (MemAddress[31:1] == `VFDCM_STATUS_CONTROL_ADDRESS) begin
	   if (DataIn[15:0] == `VFDCM_RESET_PASSWORD) DCMReset <= 1;                           //DCM Reset Password
		if (DataIn[15:0] == `VFDCM_ENABLE_PASSWORD) DCMEnable <= 1;                         //DCM Enable Password
		if (DataIn[15:0] == `VFDCM_CLEAR_PASSWORD) begin                                    //Reset/Enable Clear Password
		    DCMReset <= 0;
			 DCMEnable <= 0;
      end
   end
end

//DCM Status Register
assign Status[0] = DCMReady;
assign Status[1] = DCMLocked;
assign Status[2] = DCMPSDone;
assign Status[3] = DCMReset;
assign Status[4] = DCMEnable;
assign Status[15:5] = 11'b0;


//Status Signals
assign StatusDataOut[15:0] = (DCMStatusRead)?Status[15:0] : 16'b0;
assign DCMDataOut[15:0]= (DCMRead)?DCMOut[15:0] : 16'b0;

//Master Data Output
assign DataOut[15:0] = (StatusDataOut[15:0] | DCMDataOut[15:0]);

DCM_ADV CLOCK_DCM(.CLKFB(FeedbackBuffered),                           
                  .CLKIN(CLOCKIN),                                    //Clock Input (After Input Clock Buffer)
                  .DADDR(DCMAddress[6:0]), 
                  .DCLK(CLOCKIN),
                  .DEN(DCMEnable),
                  .DI(DataIn[15:0]),
                  .DWE(DCMWE),
                  .PSCLK(1'b0),            
                  .PSEN(1'b0),
                  .PSINCDEC(1'b0),
                  .RST(DCMReset),          
                  .CLKDV(),
                  .CLKFX(ClockOutPreBuf),
                  .CLKFX180(),
                  .CLK0(Feedback),
						.CLK2X(),
						.CLK2X180(),
						.CLK90(),
						.CLK180(),
						.CLK270(),
						.DO(DCMOut[15:0]),
						.DRDY(DCMReady),
						.LOCKED(DCMLocked),
						.PSDONE(DCMPSDone));


BUFG DCM_FEEEDBACK_BUF(.I(Feedback), .O(FeedbackBuffered));
BUFG DCM_OUTPUT_BUF(.I(ClockOutPreBuf), .O(ClockOut));

//-----------------Default DCM Settings-------------------//

//synthesis attribute CLKFX_DIVIDE of CLOCK_DCM is "4";
//synthesis attribute CLKFX_MULTIPLY of CLOCK_DCM is "2";
//synthesis translate_off
defparam CLOCK_DCM.CLKFX_DIVIDE = "4";
defparam CLOCK_DCM.CLKFX_MULTIPLY = "2";
//synthesis translate_on

//---------------------Other DCM Options---------------------//
//synthesis attribute CLK_FEEDBACK of CLOCK_DCM is "1X";
//synthesis attribute CLKDV_DIVIDE of CLOCK_DCM is "2";
//synthesis attribute CLKIN_DIVIDE_BY_2 of CLOCK_DCM is "FALSE";
//synthesis attribute CLKIN_PERIOD of CLOCK_DCM is "20";
//synthesis attribute CLKOUT_PHASE_SHIFT of CLOCK_DCM is "NONE";
//synthesis attribute DCM_PERFORMANCE_MODE of CLOCK_DCM is "MAX_RANGE";
//synthesis attribute DESKEW_ADJUST of CLOCK_DCM is "SYSTEM_SYNCHRONOUS";
//synthesis attribute DFS_FREQUENCY_MODE of CLOCK_DCM is "LOW";
//synthesis attribute DLL_FREQUENCY_MODE of CLOCK_DCM is "LOW";
//synthesis attribute DUTY_CYCLE_CORRECTION of CLOCK_DCM is "TRUE";
//synthesis attribute PHASE_SHIFT of CLOCK_DCM is "0";
//synthesis attribute STARTUP_WAIT of CLOCK_DCM is "FALSE";
//synthesis attribute FACTORY_JF of CLOCK_DCM is "F0F0";

//synthesis translate_off
defparam CLOCK_DCM.CLK_FEEDBACK = "1X";
defparam CLOCK_DCM.CLKDV_DIVIDE = "2";
defparam CLOCK_DCM.CLKIN_DIVIDE_BY_2 = "FALSE";
defparam CLOCK_DCM.CLKIN_PERIOD = "20";
defparam CLOCK_DCM.CLKOUT_PHASE_SHIFT = "NONE";
defparam CLOCK_DCM.DCM_PERFORMANCE_MODE = "MAX_RANGE";
defparam CLOCK_DCM.DESKEW_ADJUST = "SYSTEM_SYNCHRONOUS";
defparam CLOCK_DCM.DFS_FREQUENCY_MODE = "LOW";
defparam CLOCK_DCM.DLL_FREQUENCY_MODE = "LOW";
defparam CLOCK_DCM.DUTY_CYCLE_CORRECTION = "TRUE";
defparam CLOCK_DCM.PHASE_SHIFT = "0";
defparam CLOCK_DCM.STARTUP_WAIT = "FALSE";
defparam CLOCK_DCM.FACTORY_JF = "C080";		 
//synthesis translate_on

endmodule